package otso.se.network.sockets.communication.abstraction.tcp;

import java.io.IOException;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.io.Serializable;
import java.net.InetSocketAddress;
import java.net.Socket;
import java.net.SocketException;
import java.net.UnknownHostException;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

/*
 * WARNING: When to create and close an input or output stream does matter!
 * 			Be cautious whenever you have temptations of changing them!
 * 
 * (a good similar example: http://www.daniweb.com/software-development/java/threads/259042)
 */
public class TCPClient {
	final Logger logger = LoggerFactory.getLogger(TCPClient.class);

    Socket kkSocket;

    protected void openSocket(String addr, int port) {
        try {
            final InetSocketAddress serveraddr= new InetSocketAddress(addr,port);
            // 0 == any available port is taken in the bind
            final InetSocketAddress saddr = new InetSocketAddress(0);
            kkSocket = new Socket();
            kkSocket.bind(saddr);
            logger.debug("Trying to connect to " + serveraddr.getHostName() + ", port " + serveraddr.getPort());
            kkSocket.connect(serveraddr);
            logger.debug("Socket created and connected to host.");        
        } catch (UnknownHostException e) {
        	logger.error("Can't get local address");
            System.exit(1);
        } catch (SocketException e) {
        	logger.error("Error opening socket.\n"+e.getMessage());
            System.exit(1);
        } catch (IOException ep) {
        	logger.error("Error opening socket.\n"+ep.getMessage());
            System.exit(1);
        }
    }
    
    protected void closeSocket() {
        try {
            kkSocket.close();
            logger.debug("Socket closed.");
        } catch (IOException ep) {
        	logger.error("Error closing socket.");
            System.exit(1);
        }
    }

    public Object sendData(Serializable serializable) {
    	Object ret = null;
        logger.debug("Sending data...");
        
        ObjectOutputStream out = null;
        ObjectInputStream in = null;
        try {        	
        	out = new ObjectOutputStream(kkSocket.getOutputStream());
        	out.writeObject(serializable);
        	out.flush();
        	
            logger.debug("Data sent, now awaiting reply...");
            in = new ObjectInputStream(kkSocket.getInputStream());
			ret = in.readObject();
			
            logger.debug("Message received: " + ret.toString());
        } catch (IOException e) {
        	logger.error("Couldn't get I/O for the connection.");
        	e.printStackTrace();
            System.exit(1);
	    } catch (ClassNotFoundException e) {
	    	logger.error("received object's class not found in the classpath.");
            System.exit(1);
		} finally {
            try {
				in.close();
				out.close();
			} catch (IOException e) {
				logger.error("Couldn't close the input and output streams.");
			}
        }
        return ret;
    }
}